<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>坚持20秒 - 网页版</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: #f0f0f0;
            font-family: Arial, sans-serif;
        }
        #gameCanvas {
            border: 2px solid #333;
            cursor: none; /* 隐藏系统光标，用飞机替代 */
            background: #000; /* 背景色和原代码一致（黑色） */
        }
    </style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
    // 游戏全局配置
    const WINDOW_WIDTH = 800;
    const WINDOW_HEIGHT = 600;
    const FPS = 60;
    const ballNum = 50;
    const safeRadius = 150;
    const MOVE_SPEED = 5; // 方向键移动速度

    // 全局变量（对应原代码全局变量）
    let lastTime = 0;
    let attackBalls = []; // 小球数组
    let playerPlane = {}; // 飞机对象
    let isKeyDown = {}; // 方向键状态（key: 键码, value: 是否按下）
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');

    // 初始化飞机（对应原代码initPlane）
    function initPlane() {
        return new Promise((resolve) => {
            // 加载飞机图片（替换原代码loadimage）
            const planeImg = new Image();
            planeImg.src = './static/pic/plane.png'; // 保持原图片路径

            // 图片加载成功
            planeImg.onload = () => {
                playerPlane = {
                    x: WINDOW_WIDTH / 2,
                    y: WINDOW_HEIGHT / 2,
                    img: planeImg,
                    width: planeImg.width,
                    height: planeImg.height,
                    collideRadius: Math.sqrt(planeImg.width**2 + planeImg.height**2) / 3
                };
                resolve();
            };

            // 图片加载失败（用蓝色圆形替代）
            planeImg.onerror = () => {
                playerPlane = {
                    x: WINDOW_WIDTH / 2,
                    y: WINDOW_HEIGHT / 2,
                    img: null, // 无图片
                    width: 40,
                    height: 40,
                    collideRadius: 20
                };
                resolve();
            };
        });
    }

    // 初始化小球（对应原代码initBalls）
    function initBalls() {
        attackBalls = [];
        // 生成随机数（对应原代码srand+rand）
        const rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

        for (let i = 0; i < ballNum; i++) {
            const radius = 3;
            let x, y, distance;

            // 安全区逻辑（do-while循环确保不在安全区内）
            do {
                x = rand(radius, WINDOW_WIDTH - radius);
                y = rand(radius, WINDOW_HEIGHT - radius);
                const dx = x - playerPlane.x;
                const dy = y - playerPlane.y;
                distance = Math.sqrt(dx*dx + dy*dy);
            } while (distance < safeRadius + radius + playerPlane.collideRadius);

            // 小球速度（减慢后，rand(-1,1) → 速度±1，更慢）
            let speedX = rand(-1, 1);
            speedX = speedX === 0 ? 1 : speedX;
            let speedY = rand(-1, 1);
            speedY = speedY === 0 ? 1 : speedY;

            attackBalls.push({ x, y, radius, speedX, speedY });
        }
    }

    // 更新小球位置（对应原代码updateBalls）
    function updateBalls() {
        attackBalls.forEach(ball => {
            // 移动
            ball.x += ball.speedX;
            ball.y += ball.speedY;

            // 边界修正（和原代码逻辑一致）
            if (ball.x - ball.radius <= 0) {
                ball.x = ball.radius;
                ball.speedX = -ball.speedX;
            }
            if (ball.x + ball.radius >= WINDOW_WIDTH) {
                ball.x = WINDOW_WIDTH - ball.radius;
                ball.speedX = -ball.speedX;
            }
            if (ball.y - ball.radius <= 0) {
                ball.y = ball.radius;
                ball.speedY = -ball.speedY;
            }
            if (ball.y + ball.radius >= WINDOW_HEIGHT) {
                ball.y = WINDOW_HEIGHT - ball.radius;
                ball.speedY = -ball.speedY;
            }
        });
    }

    // 碰撞检测（对应原代码isCollided）
    function isCollided() {
        for (const ball of attackBalls) {
            const dx = playerPlane.x - ball.x;
            const dy = playerPlane.y - ball.y;
            const distance = Math.sqrt(dx*dx + dy*dy);
            if (distance <= playerPlane.collideRadius + ball.radius) {
                return true;
            }
        }
        return false;
    }

    // 绘制小球（对应原代码drawBall）
    function drawBall(ball) {
        ctx.fillStyle = 'red'; // 对应原代码setfillcolor(RED)
        ctx.beginPath();
        ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2); // 对应fillcircle
        ctx.fill();
    }

    // 绘制飞机（对应原代码drawPlane）
    function drawPlane() {
        if (playerPlane.img) {
            // 有图片：绘制图片（对应putimage）
            const left = playerPlane.x - playerPlane.width / 2;
            const top = playerPlane.y - playerPlane.height / 2;
            ctx.drawImage(playerPlane.img, left, top);
        } else {
            // 无图片：绘制蓝色圆形替代
            ctx.fillStyle = 'blue';
            ctx.beginPath();
            ctx.arc(playerPlane.x, playerPlane.y, playerPlane.collideRadius, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    // 绘制计时区域（对应原代码drawTimerArea）
    function drawTimerArea(insistTime) {
        const text = `已坚持：${insistTime.toFixed(2)} 秒`;

        // 设置字体（对应原代码settextstyle）
        ctx.font = '30px 微软雅黑';
        ctx.fillStyle = 'white'; // 文字颜色白色

        // 计算文字宽度（对应原代码textwidth）
        const textWidth = ctx.measureText(text).width;
        const textHeight = 30; // 字体大小近似高度

        // 绘制黑色背景矩形
        const rectPadding = 40;
        const rectWidth = textWidth + rectPadding;
        const rectHeight = 50;
        const rectX = (WINDOW_WIDTH - rectWidth) / 2;
        const rectY = 0;

        ctx.fillStyle = 'black';
        ctx.fillRect(rectX, rectY, rectWidth, rectHeight); // 对应fillrectangle

        // 绘制文字（居中）
        ctx.fillStyle = 'white';
        const textX = rectX + (rectWidth - textWidth) / 2;
        const textY = rectY + (rectHeight - textHeight) / 2 + 20; // 文字基线调整
        ctx.fillText(text, textX, textY); // 对应outtextxy
    }

    // 绘制游戏结束/胜利文字
    function drawEndText(text, color) {
        ctx.fillStyle = color;
        ctx.font = '50px 微软雅黑';
        const textWidth = ctx.measureText(text).width;
        const x = (WINDOW_WIDTH - textWidth) / 2;
        const y = WINDOW_HEIGHT / 2;
        ctx.fillText(text, x, y);
    }

    // 绘制倒计时文字（3→2→1）
    function drawCountdown(num) {
        ctx.clearRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); // 清屏
        ctx.fillStyle = 'white';
        ctx.font = '80px 微软雅黑';
        const textWidth = ctx.measureText(num).width;
        const x = (WINDOW_WIDTH - textWidth) / 2;
        const y = WINDOW_HEIGHT / 2;
        ctx.fillText(num, x, y); // 居中显示倒计时数字
    }

    // 飞机移动更新（单独提取，处理鼠标+方向键）
    function updatePlanePosition() {
        // 1. 方向键持续移动（核心修复：主循环中每帧检测，长按持续移动）
        if (isKeyDown[37]) { // 左方向键
            playerPlane.x -= MOVE_SPEED;
        }
        if (isKeyDown[39]) { // 右方向键
            playerPlane.x += MOVE_SPEED;
        }
        if (isKeyDown[38]) { // 上方向键
            playerPlane.y -= MOVE_SPEED;
        }
        if (isKeyDown[40]) { // 下方向键
            playerPlane.y += MOVE_SPEED;
        }

        // 2. 边界限制（确保飞机不超出窗口）
        playerPlane.x = Math.max(playerPlane.width / 2, playerPlane.x);
        playerPlane.x = Math.min(WINDOW_WIDTH - playerPlane.width / 2, playerPlane.x);
        playerPlane.y = Math.max(playerPlane.height / 2, playerPlane.y);
        playerPlane.y = Math.min(WINDOW_HEIGHT - playerPlane.height / 2, playerPlane.y);
    }

    // 游戏主循环（对应原代码main中的while循环）
    function gameLoop(timestamp) {
        if (!lastTime) lastTime = timestamp;
        const insistTime = (timestamp - lastTime) / 1000; // 已坚持时间

        // 清屏（对应原代码cleardevice）
        ctx.clearRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

        // 更新飞机位置（方向键持续移动+边界限制）
        updatePlanePosition();

        // 更新小球位置
        updateBalls();

        // 碰撞检测
        if (isCollided()) {
            drawEndText(`游戏结束！共坚持：${insistTime.toFixed(2)}秒`, 'red');
            return; // 结束循环
        }

        // 胜利条件（坚持20秒）
        if (insistTime >= 20.0) {
            drawEndText('恭喜你坚持到了20秒！', 'green');
            return; // 结束循环
        }

        // 绘制顺序：小球→飞机→计时区（和原代码一致）
        attackBalls.forEach(ball => drawBall(ball));
        drawPlane();
        drawTimerArea(insistTime);

        // 继续循环（对应原代码FlushBatchDraw+Sleep）
        requestAnimationFrame(gameLoop);
    }

    // 初始化事件监听（鼠标+键盘，对应原代码peekmessage）
    function initEventListeners() {
        // 鼠标移动控制飞机（实时同步，替代光标）
        canvas.addEventListener('mousemove', (e) => {
            const rect = canvas.getBoundingClientRect();
            // 计算鼠标在Canvas内的坐标（避免Canvas偏移问题）
            playerPlane.x = e.clientX - rect.left;
            playerPlane.y = e.clientY - rect.top;
        });

        // 键盘按下（仅更新状态，不移动飞机）
        document.addEventListener('keydown', (e) => {
            isKeyDown[e.keyCode] = true;
        });

        // 键盘松开（更新状态）
        document.addEventListener('keyup', (e) => {
            isKeyDown[e.keyCode] = false;
        });

        // 防止页面失去焦点后按键状态异常
        window.addEventListener('blur', () => {
            isKeyDown = {}; // 清空按键状态
        });
    }

    // 3秒倒计时逻辑
    function startCountdown() {
        return new Promise((resolve) => {
            let count = 3;
            // 绘制初始倒计时数字3
            drawCountdown(count);

            // 每1秒更新一次倒计时
            const timer = setInterval(() => {
                count--;
                if (count > 0) {
                    drawCountdown(count);
                } else {
                    clearInterval(timer);
                    resolve(); // 倒计时结束，启动游戏
                }
            }, 1000);
        });
    }

    // 初始化游戏（对应原代码initGameWindow+main）
    async function initGame() {
        // 1. 弹出开始确认对话框
        const isStart = confirm('是否开始游戏？');
        if (!isStart) {
            alert('游戏已取消');
            return; // 用户取消，终止游戏初始化
        }

        // 2. 初始化飞机（等待图片加载完成）
        await initPlane();

        // 3. 启动3秒倒计时
        await startCountdown();

        // 4. 初始化小球（倒计时结束后再生成，避免提前存在）
        initBalls();

        // 5. 初始化事件监听
        initEventListeners();

        // 6. 启动游戏循环
        requestAnimationFrame(gameLoop);
    }

    // 启动游戏
    initGame();
</script>
</body>
</html>